"""
Case Type   : cm
Case Name   : RTO模式下，dn Pending升主时故障测试-删除CmServer目录
Create At   : 2024-07
Owner       : haomeng
Description :
    1、查看集群状态
    2、开启RTO重启数据库
    3、主节点执行事务
    4、停止备节点
    5、查看集群状态
    6、执行start拉起备节点，过程中删除备机CMServer目录
        cm_ctl start -n 2
        mv $GAUSSHOME/cm/cm_server $GAUSSHOME/cm/cm_server_bak
    7、再次执行start命令
    8、查询集群状态
    9、查看启停标志文件
    10、恢复参数，恢复集群初始状态
Expect      :
    1、集群所有节点状态正常，显示Normal
    2、参数设置成功
    3、主节点执行事务成功
    4、停止备节点成功
    5、备节点备踢出集群，集群状态异常
    6、start拉起备节点操作执行成功，移除备节点cmserver目录成功
    7、拉起集群成功
    8、集群状态正常
    9、文件不存在
    10、恢复集群初始状态成功
History     :
"""

import os
import time
import unittest

from testcase.utils.CommonSH import CommonSH
from testcase.utils.Common import Common
from testcase.utils.Constant import Constant
from testcase.utils.ComThread import ComThread
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro

Primary_SH = CommonSH('PrimaryDbUser')


@unittest.skipIf(3 != Primary_SH.get_node_num(), '需1主2备环境，否则不执行')
class CmCtl(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.comsh = CommonSH('PrimaryDbUser')
        self.com = Common('PrimaryDbUser')
        self.pri_user = Node('PrimaryDbUser')
        self.sta_user = Node('Standby1DbUser')
        self.constant = Constant()
        self.table = 't_cm_tools_0242'
        self.cms_path = os.path.join(os.path.dirname(macro.DB_INSTANCE_PATH), 'cm', 'cm_server')
        self.replication = 'replication_type'
        self.recovery_parse = 'recovery_parse_workers'
        self.recovery_redo = 'recovery_redo_workers'
        self.hot_standby = 'hot_standby'
        self.default_replication = self.com.show_param(self.replication)
        self.default_recovery_parse = self.com.show_param(self.recovery_parse)
        self.default_recovery_redo = self.com.show_param(self.recovery_redo)
        self.default_hot_standby = self.com.show_param(self.hot_standby)

    def test_cm(self):
        text = '----step1:查看集群状态; expect:集群状态正常,DN主在节点1----'
        self.log.info(text)

        status = self.comsh.exec_cm_ctl('query', '-Cv', '-z ALL')
        self.log.info(status)
        AZ_status = status.splitlines()[-1]
        self.log.info(AZ_status)
        self.assertIn("cluster_state   : Normal", status)

        text = '----step2:开启RTO重启数据库; expect:参数设置成功，集群重启成功----'
        self.log.info(text)

        set_param1 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.replication} = 1')
        self.log.info(set_param1)
        set_param2 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.recovery_parse} = 4')
        self.log.info(set_param2)
        set_param3 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.recovery_redo} = 4')
        self.log.info(set_param3)
        set_param4 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.hot_standby} = off')
        self.log.info(set_param4)

        restart = self.comsh.exec_cm_ctl('stop;', 'cm_ctl start')
        self.log.info(restart)
        self.assertIn(self.constant.cm_start_success_msg, restart, '重启失败')

        text = '-----step3:主节点执行事务 expect:业务执行成功-----'
        self.log.info(text)

        sql = f"drop table if exists {self.table};" \
              f"create table {self.table}(id int,name varchar(100));" \
              f"insert into {self.table} values(generate_series(1,1000)," \
              f"'name_'||generate_series(1,1000));" \
              f"update {self.table} set name = 'cm' where id <300;" \
              f"select count(*) from {self.table};"
        self.log.info(sql)
        sql_res = self.comsh.execut_db_sql(sql)
        self.log.info(sql_res)
        self.assertIn(self.constant.INSERT_SUCCESS_MSG, sql_res, '插入数据失败')
        self.assertIn('1000', sql_res.splitlines()[-2], '查看数据失败')

        text = '-----step4:停止备节点  expect:停止成功-----'
        self.log.info(text)

        stop = self.comsh.exec_cm_ctl('stop', '-n 2',
                                      f'-D {macro.DB_INSTANCE_PATH}')
        self.log.info(stop)
        self.assertIn(self.constant.cm_stop_instance_success_msg, stop, '停止节点失败')

        text = '-----step5:查看集群状态  expect:备节点备踢出集群，集群状态异常-----'
        self.log.info(text)

        status = self.comsh.exec_cm_ctl('query', '-Cv')
        self.log.info(status)
        s_status = status.splitlines()[-1].split('|')[1]
        self.assertIn('Manually stopped', s_status, '备节点状态')

        text = '-----step6:执行start拉起备节点，过程中删除备机CMServer目录  ' \
               'expect:start拉起备节点操作执行成功，移除备节点cmserver目录成功-----'
        self.log.info(text)

        start_cmd = f'start -n 2 -D {macro.DB_INSTANCE_PATH}'
        start_res = ComThread(self.comsh.exec_cm_ctl, args=(start_cmd,))
        start_res.setDaemon(True)
        start_res.start()
        time.sleep(3)

        mv_cmserver = f'mv {self.cms_path} {self.cms_path}_bakkk'
        self.log.info(mv_cmserver)
        mv_cms_res = ComThread(self.com.get_sh_result,
                               args=(self.sta_user, mv_cmserver,))
        mv_cms_res.setDaemon(True)
        mv_cms_res.start()

        start_res.join()
        start_result = start_res.get_result()
        self.log.info(start_result)
        mv_result = mv_cms_res.get_result()
        self.log.info(mv_result)
        self.assertIn(self.constant.cm_start_instance_success_msg, start_result, '拉起节点失败')
        self.assertEqual('', mv_result, '移除cms目录失败')

        text = '-----step7:再次拉起集群  expect:拉起成功-----'
        self.log.info(text)

        start = self.comsh.exec_cm_ctl('start')
        self.log.info(start)
        self.assertIn(self.constant.cm_start_success_msg, start, '拉起失败')

        text = '------step8:查看集群状态; expect:状态正常------'
        self.log.info(text)

        status = self.comsh.exec_cm_ctl('query', '-Cv')
        self.log.info(status)
        self.assertIn("cluster_state   : Normal", status)

        text = '------step9:查看启停标志文件  expect:文件不存在------'
        self.log.info(text)

        file_path = f'ls {macro.GAUSSHOME_BIN_PATH}/cluster_manual_start*'
        cat_file1 = self.pri_user.sh(file_path).result()
        self.log.info(cat_file1)
        self.assertIn('No such file or directory', cat_file1, '启停标志文件存在')

    def tearDown(self):
        text = '------step10:恢复参数,恢复集群初始状态; expect:恢复集群状态成功------'
        self.log.info(text)

        recovery_cms = f'mv {self.cms_path}_bakkk {self.cms_path};' \
                       f'ls {self.cms_path}'
        recovery_res = self.sta_user.sh(recovery_cms).result()
        self.log.info(recovery_res)

        set_param5 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.replication} = {self.default_replication}')
        self.log.info(set_param5)
        set_param6 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.recovery_parse} = {self.default_recovery_parse}')
        self.log.info(set_param6)
        set_param7 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.recovery_redo} = {self.default_recovery_redo}')
        self.log.info(set_param7)
        set_param8 = self.comsh.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.hot_standby} = {self.default_hot_standby}')
        self.log.info(set_param8)

        stop = self.comsh.exec_cm_ctl('stop')
        self.log.info(stop)
        start = self.comsh.exec_cm_ctl('start')
        self.log.info(start)

        status = self.comsh.exec_cm_ctl('query', '-Cv')
        self.log.info(status)
        p_status = status.splitlines()[-1].split('|')[0].split('6001')[-1]
        if 'Primary' in p_status:
            self.log.info('---集群状态正常，无需恢复为初始状态---')
        else:
            recovery = Primary_SH.exec_cm_ctl(mode='switchover', param='-a')
            self.log.info(recovery)

            self.assertIn(self.constant.cm_switchover_success_msg, recovery,
                          '切换失败')

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn(f'{self.cms_path}', recovery_cms, 'cms文件存在')
        self.assertIn('cluster_state   : Normal', status, '状态异常')
        self.assertIn('P Primary Normal',
                      status.splitlines()[-1].split('|')[0].split('6001')[-1],
                      '状态异常')
        self.assertIn('S Standby Normal',
                      status.splitlines()[-1].split('|')[1].split('6002')[-1],
                      '状态异常')
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
